/**
//文档生成日期：2005.10.07
//
//(1)概述：
//类名称：RssFeedOpen
//类说明：
//??	 “读取Rss Feed新闻”的Form界面
* 
//所在子系统：RssOwlMIDlet
//
//系统总描述:
	    我们提供的RSS无线阅读器J2ME版本[开源]是一个可以下载到手机(例如Nokia7610)或者其他无线手持设备(例如PocketPC)的应用程序，用来阅读存在于Internet中广泛的RSS新闻源。

	 子系统描述：
		RSS无线阅读器的功能列表：
	RSS Feed列表
		添加Rss Feed
		编辑Rss Feed
		删除Rss Feed
	读取Rss Feed新闻
		查看新闻摘要
		重新读取Rss Feed新闻
	关于我


//(2)历史记录:
//创建人: 郑昀(2005.10.07)
//联系我: Google Talk >> zhengyun@gmail.com
//Blogs:    http://blog.csdn.net/zhengyun_ustc/以及http://www.cnblogs.com/zhengyun_ustc

//(3)版权声明:
//由于我这个版本的RSS J2ME阅读器也是基于Tommi和garrey源代码基础上改编而来的，
//所以决定遵照GPL协议的大意开放源代码，您可以自由传播和修改，在遵照GPL协议的约束条件的前提下。

//(4)相关资源:
1：《[J2ME]RSSOwlMidlet(RSS无线阅读器)开源说明》
2：《[J2ME]RSSOwlMidlet(RSS无线阅读器)设计说明》
3：下载源代码：

////////////////////////////////////////////////////////////////////*/
package com.zemo.view;

import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.List;
import javax.microedition.lcdui.TextField;

import com.zemo.control.GUIController;
import com.zemo.model.RssFeed;
import com.zemo.model.RssFeedParser;
import com.zemo.model.RssItem;
import com.zemo.tools.SResources;

/**********************************************************
//RssFeedOpen
//
//Class Description:
//	显示当前选中的Rss Feed的新闻列表,以新闻条目主题列表方式显示。提供菜单命令有：
*   读取新闻
*   添加书签
*   编辑书签
*   删除书签
*   关于我
//
//Author:
//zhengyun@zemo 2005.10.07
//
**********************************************************/
public class RssFeedOpen extends Form
						implements Runnable{
    private GUIController 	 controller;
	private Display     	 m_display;          // The display for this MIDlet
	private Command     	 m_openHeaderCmd;    // The open header command
    private Command    	 m_backHeaderCmd;    // The back to bookmark list command
    private Command    	 m_updateCmd;        // The update headers command
	private TextField 		 errorTextField;
	
	private boolean     	 m_getPage;          // The noticy flag for HTTP
	private List        	 m_headerList;       // The header list
	private RssFeedParser   m_curRssParser; 	 // The currently selected RSS
	
	private Thread     	 m_netThread;        // The thread for networking
	private static Image 	 m_iconOpen = SResources.getImage(
			SResources.IMG_UNREADFEED);
	private static Image   m_iconError = SResources.getImage(
			SResources.IMG_ERROR);
	private int			 m_nErrorTextFieldId;
	private int			 m_nErrorImageFieldId;
	private WaitFlash 		 m_WaitFlash;
    
	
	/**********************************************************
	//	 RssFeedOpen::RssFeedOpen
	//
	//	 Description:
	//	  初始化界面:
	 * 		初始化菜单命令;
	 * 		初始化新闻条目列表;
	 * 		本Form其实也是一个Thread,我们为了让后台来获取并解析RSS XML,所以启动线程
	 * 		加载图像
	//
	//	 Parameters:
	//	 Return Values:
	//   Remark:
	 * 
	//	 Author:
	//	      zhengyun@zemo 2005.10.07
	//
	**********************************************************/
	public RssFeedOpen(String title, GUIController control){
		super(title);
    	controller = control;
		m_nErrorTextFieldId = -1;
		m_nErrorImageFieldId = -1;
		m_display = controller.rssMidlet.getCurrentDisplay();
		
		m_openHeaderCmd     = new Command(SResources.MENU_COMMAND_VIEWDETAIL, Command.SCREEN, 1);
        m_backHeaderCmd     = new Command(SResources.MENU_COMMAND_BACKCMD, Command.BACK,1);
        m_updateCmd         = new Command(SResources.MENU_COMMAND_UPDATENEWS, Command.SCREEN, 2);
		initializeHeadersList();
		
    	this.setCommandListener(new RssFeedOpenListener());
		
		/** Initialize thread for http connection operations */
        m_netThread = new Thread(this);
        m_netThread.start();
	}


	/**********************************************************
	//	 RssFeedOpen::updateHeaders
	//
	//	 Description:
	//	  更新新闻条目列表:
	 * 		先将当前新闻列表全部删除
	 * 		再告诉后台线程,可以去读取并解析RSS Feed了
	//
	//	 Parameters:
	//	 Return Values:
	//   Remark:
	 * 
	//	 Author:
	//	      zhengyun@zemo 2005.10.07
	//
	**********************************************************/
    public void updateHeaders() {
		System.out.println("/** updateHeaders */");
		
		// 将当前新闻列表全部删除
		deleteAll();
		if(m_WaitFlash == null)
		{
			// 当前没有等候动画时,我们需要创建一个
			m_WaitFlash = new WaitFlash();
			m_WaitFlash.setMessage("正在读取新闻列表，请稍等...");
			m_display.setCurrent(m_WaitFlash);			
		}
		else
		{
			m_display.setCurrent(m_WaitFlash);
		}
		System.out.println("设置了等待画面!");
        if(m_curRssParser.getRssFeed().getUrl().length()>0) {
            m_getPage = true;
        }
    }
	
	/**********************************************************
	//	 RssFeedOpen::deleteAll
	//
	//	 Description:
	//	  将当前新闻列表全部删除
	//
	//	 Parameters:
	//	 Return Values:
	//   Remark:
	 * 由于MIDP 2.0中才定义了List的deleteAll()方法,
	 * 但是MIDP1.0中List支持delete(int itemNum).
	 * 所以在MIDP1.0中,可以使用List的size()得到当前List中的Item的数量,
	 * 然后使用for循环delete(int itemNum),这样在MIDP1.0中实现deleteAll的功能。
	 * 但这么for循环删除有一个非常奇怪的地方,好像是隔一个删一个，导致无法删除干净?!
	 * 所以最后不得不采用while循环删除第一个元素的办法!这也许是一个MIDP1.0的bug。
	//	 Author:
	//	      zhengyun@zemo 2005.10.07
	//
	**********************************************************/
	private synchronized void delete()
	{
		System.out.println("!-- RssFeedOpen::Enter deleteAll --!");
		
		// 下面的删除代码只能隔一个删一个m_headerList的元素，导致无法删除干净
		/*for(int i = 0;i < m_headerList.size();i++){
			
			m_headerList.delete(i);
			System.out.println("delete>>" + i);
		}*/
		
		// 这样才能完全删除:
		while(m_headerList.size()>0)
            m_headerList.delete(0);
	}
	
	/**********************************************************
	//	 RssFeedOpen::appendRssItem
	//
	//	 Description:
	//	  向List中添加Rss Item
	//
	//	 Parameters:
	//	 Return Values:
	//   Remark:
	 * 
	//	 Author:
	//	      zhengyun@zemo 2005.10.07
	//
	**********************************************************/
	public void appendRssItem(String title)
	{
		setCurrentDispalyToHeaderList();
		int nId = m_headerList.append(title, m_iconOpen);
		System.out.println("/** appendRssItem:append item id=" + nId);
	}
	
	/**********************************************************
	//	 RssFeedOpen::setRss
	//
	//	 Description:
	//	  设置当前需要去读取哪一个Rss Feed
	//
	//	 Parameters:
	 * 		feed: 输入feed
	//	 Return Values:
	//   Remark:
	 * 
	//	 Author:
	//	      zhengyun@zemo 2005.10.07
	//
	**********************************************************/
	public void setRss(RssFeed feed){
		m_curRssParser = new RssFeedParser( feed , controller);
		
		m_curRssParser.openForm = this;
		
        if( m_curRssParser.getRssFeed().getItems().size() == 0 ) {
			
            /** Update RSS feed headers only if this is a first time */
            updateHeaders();
        } else {
			System.out.println("/** fillHeadersList */");
            /**
             * Show currently selected RSS feed
             * headers without updating them
             */
            fillHeadersList();
        }
	}
	
	/**********************************************************
	//	 RssFeedOpen::fillHeadersList
	//
	//	 Description:
	//	  根据当前Rss Feed对应的类实体中存储的Rss Item列表，重新填充界面上的List
	//
	//	 Parameters:
	//	 Return Values:
	//   Remark:
	 * 
	//	 Author:
	//	      zhengyun@zemo 2005.10.07
	//
	**********************************************************/
    private void fillHeadersList() {
		System.out.println("/** Enter fillHeadersList */");
		deleteAll();
		
		RssFeed feed = m_curRssParser.getRssFeed();
		System.out.println("重新采用RssFeed:" + feed.getName());
        for(int i = 0; i < m_curRssParser.getRssFeed().getItems().size(); i++){
           
            RssItem r = (RssItem)feed.getItems().elementAt(i);
            m_headerList.append( r.getTitle(), m_iconOpen );
        }
		// 一定要在重置了新闻列表后,把m_headerList设置为焦点,否则屏幕上会没有效果!
		setCurrentDispalyToHeaderList();
    }
	
	/**********************************************************
	//	 RssFeedOpen::initializeHeadersList
	//
	//	 Description:
	//	  Initialize RSS headers list
	//
	//	 Parameters:
	//	 Return Values:
	//   Remark:
	 * 
	//	 Author:
	//	      zhengyun@zemo 2005.10.07
	//
	**********************************************************/
    private void initializeHeadersList() {
		System.out.println("/** Enter initializeHeadersList */");
        m_headerList = new List(SResources.FORM_TITLE_READRSSFEED, List.IMPLICIT);
        m_headerList.addCommand(m_openHeaderCmd);
        m_headerList.addCommand(m_backHeaderCmd);
        m_headerList.addCommand(m_updateCmd);
        m_headerList.setCommandListener(new RssFeedOpenListener());
    }
	
	/**********************************************************
	//	 RssFeedOpen::run
	//
	//	 Description:
	//	  Run method is used to get RSS feed with HttpConnection
	//
	//	 Parameters:
	//	 Return Values:
	//   Remark:
	 * 
	//	 Author:
	//	      zhengyun@zemo 2005.10.07
	//
	**********************************************************/
    public void run(){
        /* Use networking if necessary */
        long lngStart;
        long lngTimeTaken;
        while(true) {
            try {
				//  我们是依靠m_getPage来判断是否去得到并解析Rss XML的.
				//  如果当前m_getPage是false,那么本线程就只能先睡眠一段时间了.
                if( m_getPage ) {
                    try {
						if(m_nErrorTextFieldId > 0)
						{
							this.delete(m_nErrorTextFieldId);
						}
						if(m_nErrorImageFieldId > 0)
						{
							this.delete(m_nErrorImageFieldId);
						}
                        /** Get RSS feed */
						System.out.println("/** m_curRssParser.parseRssFeed(); */");
                        if(m_curRssParser.parseRssFeed())
							setCurrentDispalyToHeaderList();
                        else
						{
							this.addCommand(m_backHeaderCmd);
							
							m_WaitFlash = null;
						}
                    }catch(Exception e) {
                        /** Error while parsing RSS feed */
                        System.out.println("Error: " + e.getMessage());
						
						errorTextField = 
							new TextField("RSS提示信息 : ",
									"\n无法解析Rss Feed:\n" + 
	                                m_curRssParser.getRssFeed().getUrl(),
	                                64, TextField.ANY);
						this.addCommand(m_backHeaderCmd);
						
						// 在添加元素到界面上时,必须记下插入的id,这样下次解析RssFeed
						// 时就可以先行删除这些元素了,不至于造成重复插入
						m_nErrorImageFieldId = this.append(m_iconError);
						m_nErrorTextFieldId = this.append(errorTextField);
						m_display.setCurrent(this);
						m_WaitFlash = null;
						
                    }
                    m_getPage = false;
                }
                lngStart = System.currentTimeMillis();
                lngTimeTaken = System.currentTimeMillis() - lngStart;
                if(lngTimeTaken < 100)
                    m_netThread.sleep(75 - lngTimeTaken);
            } catch (InterruptedException e) {
                break;
            }
        }
    }
	
	/**********************************************************
	//	 RssFeedOpen::setCurrentDispalyToHeaderList
	//
	//	 Description:
	//	  设置画面到Header List
	//
	//	 Parameters:
	//	 Return Values:
	//   Remark:
	 * 
	//	 Author:
	//	      zhengyun@zemo 2005.10.07
	//
	**********************************************************/
	public void setCurrentDispalyToHeaderList()
	{
		System.out.println("设置画面到Header List!");
		m_display.setCurrent(m_headerList);
		if(m_WaitFlash != null)
		{
			// 销毁等候动画Form
			m_WaitFlash = null;
		}
	}

	/*
     * 内部监听器，监听器监听所有Command事件，并把事件响应推出来让控制器处理
     */
    private class RssFeedOpenListener implements CommandListener{ 
    	public void commandAction(Command command, Displayable disp){
			if(command == m_backHeaderCmd){
				System.out.println("Back Menu!");
				controller.handleEvent(GUIController.EventID.EVENT_VIEW_BACK,null);
	        }
			else if(command == m_openHeaderCmd || (command == List.SELECT_COMMAND &&
	                m_display.getCurrent() == m_headerList)){
	            int ind = ((List)disp).getSelectedIndex();
	            if(ind == -1)
	                return;
				Object[] args = {m_curRssParser.getRssFeed().getItems().elementAt(ind)};    		
				controller.handleEvent(GUIController.EventID.EVENT_VIEW_RSS_ITEM,args);
			}
			else if(command == m_updateCmd){
	            int ind = ((List)disp).getSelectedIndex();
	            if(ind == -1)
	                return;
				Object[] args={m_curRssParser.getRssFeed().getItems().elementAt(ind)};    		
				controller.handleEvent(GUIController.EventID.EVENT_UPDATE_RSS_ITEMS,args);
			}
    	}
    }//end inner class
}
